home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / oldwish / old / wishDisplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-10  |  53.2 KB  |  1,731 lines

  1. /* 
  2.  * fsflatDisplay.c --
  3.  *
  4.  *    Routines for layout and display for the file system flat display.
  5.  *
  6.  * Copyright 1987 Regents of the University of California
  7.  * All rights reserved.
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: fsflatDisplay.c,v 1.1 88/10/03 12:47:25 mlgray Exp $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. typedef    int    Boolean;
  22. #define    FALSE    0
  23. #define TRUE    1
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include "time.h"
  27. #include <sys/dir.h>    /* included only for MAXNAMLEN */
  28. #include "string.h"
  29. #include "sx.h"
  30. #include "util.h"
  31. #include "monitorClient.h"
  32. #include "fsflatInt.h"
  33.  
  34. /*
  35.  * Include cursor declarations and definitions.
  36.  * flat.cursor defines the regular flat display cursor and wait.cursor defines
  37.  * the cursor used while the display is busy.
  38.  */
  39. #include "flat.cursor"
  40. #include "wait.cursor"
  41.  
  42. /*
  43.  * The flat cursor is the regular cursor when the display is
  44.  * idle.  The wait cursor indicates that the display is working
  45.  * away on something.  The regular cursor can be redefined by
  46.  * users, if they wish. (Well... sometime that will be possible...)
  47.  */
  48. static        Cursor        flatCursor = -1;
  49. static        Cursor        waitCursor = -1;
  50.  
  51. /* Default commands in the overall command table. */
  52. static    CmdInfo    commands[] = {
  53.     {"bind",        FsflatBindCmd},
  54.     {"changeDirectory",    FsflatChangeDirCmd},
  55.     {"quit",        FsflatQuitCmd},
  56.     {"close",        FsflatCloseCmd},
  57.     {"redraw",        FsflatRedrawCmd},
  58.     {"selection",    FsflatSelectionCmd},
  59.     {"resize",        FsflatResizeCmd},
  60.     {"toggleSelection",    FsflatToggleSelectionCmd},
  61.     {"toggleSelEntry",    FsflatToggleSelEntryCmd},
  62.     {"groupBind",    FsflatGroupBindCmd},
  63.     {"open",        FsflatOpenCmd},
  64.     {"sortFiles",    FsflatSortFilesCmd},
  65.     {"setFields",    FsflatChangeFieldsCmd},
  66.     {"defineGroup",    FsflatDefineGroupCmd},
  67.     {"changeGroup",    FsflatChangeGroupCmd},
  68.     {"pattern",        FsflatPatternCompareCmd},
  69.     {"menu",        FsflatMenuCmd},
  70.     {"exec",        FsflatExecCmd},
  71.     {(char *) NULL,    (int (*)()) NULL}
  72. };
  73.  
  74. /*
  75.  * Number of open windows, for graceful exit when we close them all.
  76.  */
  77. int    fsflatWindowCount = 0;
  78.  
  79. /*
  80. /*
  81.  * Used before defined.
  82.  */
  83. extern    void    GetColumnWidthInfo();
  84. extern    int    GetMaxEntryWidth();
  85. extern    void    FigureWindowSize();
  86.  
  87.  
  88.  
  89. /*
  90.  *----------------------------------------------------------------------
  91.  *
  92.  * FsflatCreate --
  93.  *
  94.  *    Create an fsflat window.
  95.  *
  96.  * Results:
  97.  *    A pointer to the created FsflatWindow structure, or NULL if the
  98.  *    call failed.
  99.  *
  100.  * Side effects:
  101.  *    A new fsflat window will be created and displayed.
  102.  *
  103.  *----------------------------------------------------------------------
  104.  */
  105. FsflatWindow *
  106. FsflatCreate(aWindow, dir)
  107.     FsflatWindow    *aWindow;    /* parent window */
  108.     char        *dir;        /* directory to start in */
  109. {
  110.     FsflatWindow    *newWindow;
  111.     struct    stat    dirAtts;
  112.     Tx_WindowInfo    info;
  113.     static        char    *args[] = {"/bin/csh", "-i", NULL};
  114.     XSizeHints        sizeHints;
  115.     XGCValues        gcValues;
  116.  
  117.     newWindow = (FsflatWindow *) malloc(sizeof (FsflatWindow));
  118.     if (dir != NULL) {
  119.     /* quick hack until i fix selection problems */
  120.     if (dir[strlen(dir) - 1] == ' ') {
  121.         dir[strlen(dir) - 1] = '\0';
  122.     }
  123.     if (Util_CanonicalDir(dir, NULL, newWindow->dir) == NULL) {
  124.         /* error message returned in newWindow->dir */
  125.         /* if null, then we were called from main() anyway */
  126.         if (aWindow->interp == NULL) {
  127.         Sx_Panic(fsflatDisplay, newWindow->dir);
  128.         }
  129.         strcpy(aWindow->interp->result, newWindow->dir);
  130.         free(newWindow);
  131.         return NULL;
  132.     }
  133.     } else {
  134.     strcpy(newWindow->dir, aWindow->dir);
  135.     }
  136.     if (lstat(newWindow->dir, &dirAtts)
  137.         != 0) {
  138.     /* if null, then we were called from main() anyway */
  139.     if (aWindow->interp == NULL) {
  140.         sprintf(fsflatErrorMsg,
  141.             "Can't get attributes for %s.  Maybe it doesn't exist",
  142.             newWindow->dir);
  143.         Sx_Panic(fsflatDisplay, fsflatErrorMsg);
  144.     }
  145.     sprintf(aWindow->interp->result,
  146.         "Can't get attributes for %s.  Maybe it doesn't exist",
  147.         newWindow->dir);
  148.     free(newWindow);
  149.     return NULL;
  150.     }
  151.     /* Put name of dir in the editable string for the title display window */
  152.     strcpy(newWindow->editDir, newWindow->dir);
  153.  
  154.     if ((dirAtts.st_mode & S_IFMT) != S_IFDIR) {    /* not a directory */
  155.     if (aWindow->interp == NULL) {
  156.         sprintf(fsflatErrorMsg, "%s is not a directory", newWindow->dir);
  157.         Sx_Panic(fsflatDisplay, fsflatErrorMsg);
  158.     }
  159.     sprintf(aWindow->interp->result, "%s is not a directory",
  160.         newWindow->dir);
  161.     free(newWindow);
  162.     return NULL;
  163.     }
  164.      
  165.     if (chdir(newWindow->dir) != 0) {
  166.     if (aWindow->interp == NULL) {
  167.         sprintf(fsflatErrorMsg,
  168.             "Couldn't change directories to %s", newWindow->dir);
  169.         Sx_Panic(fsflatDisplay, fsflatErrorMsg);
  170.     }
  171.     sprintf(aWindow->interp->result,
  172.         "Couldn't change directories to %s", newWindow->dir);
  173.     free(newWindow);
  174.     return NULL;
  175.     }
  176.     strcpy(fsflatCurrentDirectory, newWindow->dir);
  177.  
  178.     newWindow->foreground = aWindow->foreground;
  179.     newWindow->background = aWindow->background;
  180.     newWindow->selection = aWindow->selection;
  181.     newWindow->border = aWindow->border;
  182.     newWindow->borderWidth = aWindow->borderWidth;
  183.     newWindow->fontPtr = aWindow->fontPtr;
  184.     newWindow->titleForeground = aWindow->titleForeground;
  185.     newWindow->titleBackground = aWindow->titleBackground;
  186.     newWindow->titleBorder = aWindow->titleBorder;
  187.     newWindow->titleFontPtr = aWindow->titleFontPtr;
  188.     newWindow->txForeground = aWindow->txForeground;
  189.     newWindow->txBackground = aWindow->txBackground;
  190.     newWindow->txBorder = aWindow->txBorder;
  191.     newWindow->menuForeground = aWindow->menuForeground;
  192.     newWindow->menuBackground = aWindow->menuBackground;
  193.     newWindow->sortForeground = aWindow->sortForeground;
  194.     newWindow->sortBackground = aWindow->sortBackground;
  195.     newWindow->fieldsForeground = aWindow->fieldsForeground;
  196.     newWindow->fieldsBackground = aWindow->fieldsBackground;
  197.     newWindow->entryForeground = aWindow->entryForeground;
  198.     newWindow->entryBackground = aWindow->entryBackground;
  199.     newWindow->scrollForeground = aWindow->scrollForeground;
  200.     newWindow->scrollBackground = aWindow->scrollBackground;
  201.     newWindow->scrollElevator = aWindow->scrollElevator;
  202.     newWindow->geometry = aWindow->geometry;
  203.     newWindow->firstElement = UNINITIALIZED;
  204.     newWindow->numGroups = UNINITIALIZED;
  205.     newWindow->numHiddenGroups = 0;
  206.     newWindow->hideEmptyGroupsP = aWindow->hideEmptyGroupsP;
  207.  
  208.     /*
  209.      * Create the first window and subwindows and use the window id to
  210.      * identify the application's data.
  211.      */
  212.     if (newWindow->geometry != NULL) {
  213.     (void) XParseGeometry(newWindow->geometry, &sizeHints.x, &sizeHints.y,
  214.         &sizeHints.width, &sizeHints.height);
  215.     }
  216.     newWindow->surroundingWindow = XCreateSimpleWindow(fsflatDisplay,
  217.         DefaultRootWindow(fsflatDisplay), sizeHints.x, sizeHints.y,
  218.     sizeHints.width, sizeHints.height, newWindow->borderWidth,
  219.         newWindow->border, newWindow->background);
  220.     if (newWindow->surroundingWindow == 0) {
  221.     if (aWindow->interp == NULL) {
  222.         Sx_Panic(fsflatDisplay, "Couldn't create a new window.");
  223.     }
  224.     sprintf(aWindow->interp->result, "couldn't create a new window");
  225.     goto cleanUp;
  226.     }
  227.     /* for window icon */
  228.     XStoreName(fsflatDisplay, newWindow->surroundingWindow, newWindow->dir);
  229.  
  230.     /* Create textGc */
  231.     gcValues.foreground = aWindow->foreground;
  232.     gcValues.background = aWindow->background;
  233.     gcValues.font = newWindow->fontPtr->fid;
  234.     newWindow->textGc = XCreateGC(fsflatDisplay, newWindow->surroundingWindow,
  235.         GCForeground | GCBackground | GCFont, &gcValues);
  236.     /* Create reverseGc */
  237.     gcValues.foreground = aWindow->background;
  238.     gcValues.background = aWindow->foreground;
  239.     gcValues.font = newWindow->fontPtr->fid;
  240.     newWindow->reverseGc = XCreateGC(fsflatDisplay,
  241.         newWindow->surroundingWindow,
  242.         GCForeground | GCBackground | GCFont, &gcValues);
  243.  
  244.  
  245.     /*
  246.      * To get a nice divider between the title/entry window and the display
  247.      * window, create the windows with no border and create a divider as
  248.      * a separate, thin, window.  The title window is also a command entry
  249.      * window which is why I don't just use Sx_TitleCreate().
  250.      */
  251.     newWindow->titleWindow = Sx_CreatePacked(fsflatDisplay,
  252.         newWindow->surroundingWindow,
  253.         SX_TOP, Sx_DefaultHeight(fsflatDisplay, newWindow->titleFontPtr),
  254.         0, 0, newWindow->titleBorder, (Window) 0,
  255.         newWindow->titleBackground);
  256.     if (newWindow->titleWindow == 0) {
  257.     if (aWindow->interp == NULL) {
  258.         Sx_Panic(fsflatDisplay, "Couldn't create title window.");
  259.     }
  260.     sprintf(aWindow->interp->result, "couldn't create title window");
  261.     goto cleanUp;
  262.     }
  263.     /* Put "title" in window. */
  264.     Sx_EntryMake(fsflatDisplay, newWindow->titleWindow, "Directory:  ",
  265.         newWindow->titleFontPtr, newWindow->titleForeground,
  266.         newWindow->titleBackground, newWindow->editDir,
  267.         sizeof (newWindow->editDir));
  268.  
  269.     newWindow->txOutsideWindow = Sx_CreatePacked(fsflatDisplay,
  270.         newWindow->surroundingWindow,
  271.         SX_BOTTOM, 8 * Sx_DefaultHeight(fsflatDisplay, newWindow->fontPtr),
  272.         0, 0, newWindow->txBorder, (Window) 0, newWindow->txBackground);
  273.  
  274.     /* Unless i can get this info from Sx, how else can I do it? */
  275.     {
  276.     Window    dummy1;
  277.     int    x, y, width, height, border_width, dummy2;
  278.  
  279.     if (XGetGeometry(fsflatDisplay, newWindow->txOutsideWindow, &dummy1,
  280.         &x, &y, &width, &height, &border_width, &dummy2) == 0) {
  281.         Sx_Panic(fsflatDisplay, "Couldn't get tx window geometry.");
  282.     }
  283.     info.width = width;
  284.     }
  285.  
  286.     /* Create first divider */
  287.     newWindow->divider1Window = Sx_CreatePacked(fsflatDisplay,
  288.         newWindow->surroundingWindow,
  289.         SX_TOP, 1, 0, 0, newWindow->border, (Window) 0, newWindow->border);
  290.     if (newWindow->divider1Window == 0) {
  291.     if (aWindow->interp == NULL) {
  292.         Sx_Panic(fsflatDisplay,
  293.             "Couldn't create the first border between windows.");
  294.     }
  295.     sprintf(aWindow->interp->result,
  296.         "couldn't create the first border between windows");
  297.     goto cleanUp;
  298.     }
  299.     newWindow->menuBar = Sx_CreatePacked(fsflatDisplay,
  300.         newWindow->surroundingWindow, SX_TOP,
  301.         Sx_DefaultHeight(fsflatDisplay, newWindow->titleFontPtr), 0, 0,
  302.         newWindow->menuForeground, (Window) 0, newWindow->menuBackground);
  303.     /* Create next divider */
  304.     newWindow->divider2Window = Sx_CreatePacked(fsflatDisplay,
  305.         newWindow->surroundingWindow,
  306.         SX_TOP, 1, 0, 0, newWindow->border, (Window) 0, newWindow->border);
  307.     if (newWindow->divider2Window == 0) {
  308.     if (aWindow->interp == NULL) {
  309.         Sx_Panic(fsflatDisplay,
  310.             "Couldn't create the second border between windows.");
  311.     }
  312.     sprintf(aWindow->interp->result,
  313.         "couldn't create the second border between windows");
  314.     goto cleanUp;
  315.     }
  316.     newWindow->sortWindow = Sx_TitleCreate(fsflatDisplay,
  317.     newWindow->surroundingWindow,
  318.     SX_TOP, Sx_DefaultHeight(fsflatDisplay, newWindow->fontPtr), 0,
  319.     newWindow->fontPtr,
  320.     newWindow->sortForeground, newWindow->sortBackground,
  321.     newWindow->sortBackground, NULL, NULL, NULL);
  322.     if (newWindow->sortWindow == 0) {
  323.     if (aWindow->interp == NULL) {
  324.         Sx_Panic(fsflatDisplay, "Couldn't create the sort window.");
  325.     }
  326.     sprintf(aWindow->interp->result, "couldn't create the sort window");
  327.     goto cleanUp;
  328.     }
  329.     newWindow->divider3Window = Sx_CreatePacked(fsflatDisplay,
  330.         newWindow->surroundingWindow,
  331.         SX_TOP, 1, 0, 0, newWindow->border, (Window) 0, newWindow->border);
  332.     if (newWindow->divider3Window == 0) {
  333.     if (aWindow->interp == NULL) {
  334.         Sx_Panic(fsflatDisplay,
  335.             "Couldn't create the third border between windows.");
  336.     }
  337.     sprintf(aWindow->interp->result,
  338.         "couldn't create the third border between windows");
  339.     goto cleanUp;
  340.     }
  341.     newWindow->fieldsWindow = Sx_TitleCreate(fsflatDisplay,
  342.     newWindow->surroundingWindow,
  343.     SX_TOP, Sx_DefaultHeight(fsflatDisplay, newWindow->fontPtr), 0,
  344.     newWindow->fontPtr,
  345.     newWindow->fieldsForeground, newWindow->fieldsBackground,
  346.     newWindow->fieldsBackground, NULL, NULL, NULL);
  347.     if (newWindow->fieldsWindow == 0) {
  348.     if (aWindow->interp == NULL) {
  349.         Sx_Panic(fsflatDisplay, "Couldn't create the fields window.");
  350.     }
  351.     sprintf(aWindow->interp->result, "couldn't create fields window");
  352.     goto cleanUp;
  353.     }
  354.     /* Create next divider */
  355.     newWindow->divider4Window = Sx_CreatePacked(fsflatDisplay,
  356.         newWindow->surroundingWindow,
  357.         SX_TOP, 1, 0, 0, newWindow->border, (Window) 0, newWindow->border);
  358.     if (newWindow->divider4Window == 0) {
  359.     if (aWindow->interp == NULL) {
  360.         Sx_Panic(fsflatDisplay,
  361.             "Couldn't create the fourth border between windows.");
  362.     }
  363.     sprintf(aWindow->interp->result,
  364.         "couldn't create the fourth border between windows");
  365.     goto cleanUp;
  366.     }
  367.  
  368.     /*
  369.      * Is 1 really the size I want for the scrollbar border?
  370.      */
  371.     newWindow->scrollWindow = Sx_ScrollbarCreate(fsflatDisplay,
  372.         newWindow->surroundingWindow,
  373.         SX_RIGHT, 1, newWindow->scrollForeground,
  374.         newWindow->scrollBackground,
  375.         newWindow->scrollElevator, FsflatScroll, newWindow);
  376.     if (newWindow->scrollWindow == 0) {
  377.     if (aWindow->interp == NULL) {
  378.         Sx_Panic(fsflatDisplay, "Couldn't create the scroll bar.");
  379.     }
  380.     sprintf(aWindow->interp->result, "couldn't create the scrollbar");
  381.     goto cleanUp;
  382.     }
  383.     /* Create next divider */
  384.     newWindow->divider5Window = Sx_CreatePacked(fsflatDisplay,
  385.         newWindow->surroundingWindow, SX_RIGHT, 1, 0, 0, newWindow->border,
  386.         (Window) 0, newWindow->border);
  387.     if (newWindow->divider5Window == 0) {
  388.     if (aWindow->interp == NULL) {
  389.         Sx_Panic(fsflatDisplay,
  390.             "Couldn't create the fifth border between windows.");    
  391.     }
  392.     sprintf(aWindow->interp->result,
  393.         "couldn't create the fifth border between windows");
  394.     goto cleanUp;
  395.     }
  396. #ifdef NOTDEF
  397. /* what was this for in X10? */
  398.     tx_RegisterPtr = FALSE;
  399. #endif /* NOTDEF */
  400.     info.source = NULL;
  401.     info.fontPtr = newWindow->fontPtr;
  402.     info.height = 4 * Sx_DefaultHeight(fsflatDisplay, newWindow->fontPtr);
  403.     info.foreground = newWindow->txForeground;
  404.     info.background = newWindow->txBackground;
  405.     info.flags = MX_RAW;
  406.     Tx_GetTermAndTitle(newWindow->txOutsideWindow, NULL, &info);
  407.     XStoreName(fsflatDisplay, newWindow->txOutsideWindow, info.title);
  408.     Tx_Make(fsflatDisplay, newWindow->txOutsideWindow, &info, Tx_InputProc,
  409.         (ClientData) NULL);
  410.     Tx_Shell(fsflatDisplay, newWindow->txOutsideWindow, &info, args);
  411.     /* Create next divider */
  412.     newWindow->divider6Window = Sx_CreatePacked(fsflatDisplay,
  413.         newWindow->surroundingWindow,
  414.         SX_BOTTOM, 1, 0, 0, newWindow->border, (Window) 0,
  415.         newWindow->border);
  416.     if (newWindow->divider6Window == 0) {
  417.     if (aWindow->interp == NULL) {
  418.         Sx_Panic(fsflatDisplay,
  419.             "Couldn't create the sixth border between windows.");
  420.     }
  421.     sprintf(aWindow->interp->result,
  422.         "couldn't create the sixth border between windows");
  423.     goto cleanUp;
  424.     }
  425.     /* Create display subwindow */
  426.     newWindow->displayWindow = Sx_CreatePacked(fsflatDisplay,
  427.         newWindow->surroundingWindow,
  428.         SX_TOP, 0, 1, 0, newWindow->border, (Window) 0,
  429.         newWindow->background);
  430.     if (newWindow->displayWindow == 0) {
  431.     if (aWindow->interp == NULL) {
  432.         Sx_Panic(fsflatDisplay, "Couldn't create the display window.");
  433.     }
  434.     sprintf(aWindow->interp->result, "couldn't create display window");
  435. cleanUp:
  436.     if (newWindow->surroundingWindow != NULL) {
  437.         XDestroySubwindows(fsflatDisplay, newWindow->surroundingWindow);
  438.         XDestroyWindow(fsflatDisplay, newWindow->surroundingWindow);
  439.     }
  440.     free(newWindow);
  441.     return NULL;
  442.     }
  443.  
  444.     /*
  445.      * Increment the window reference count and enter the window information
  446.      * structure into the fsflatWindowContext.
  447.      */
  448.     fsflatWindowCount++;
  449.     XSaveContext(fsflatDisplay, newWindow->surroundingWindow,
  450.         (caddr_t) fsflatWindowContext, newWindow);
  451.  
  452.     /*
  453.      * Start up the display with newWindow->dir as the directory of the display.
  454.      * FsflatInit() will map the surrounding window.  It may first change
  455.      * its size.
  456.      */
  457.     FsflatInit(newWindow);
  458.     newWindow->firstElement = 1;    /* start displaying from beginning */
  459.     /*
  460.      * FsflatSetPositions() and FsflatRedraw() will be called as a result
  461.      * of the handlers, since Sx stuff generates an ExposureMask event.
  462.      * This means I don't need to call them here explicitly.
  463.      */
  464.  
  465.     /* For the handlers, should I pass the window or newWindow as clientData? */
  466.     Sx_HandlerCreate(fsflatDisplay, newWindow->surroundingWindow,
  467.         EnterWindowMask, FsflatHandleEnterEvent, newWindow);
  468.     /*
  469.      * Select these button events in the display window, but pass the
  470.      * surrounding window to the handlers.
  471.      */
  472.     Sx_HandlerCreate(fsflatDisplay, newWindow->displayWindow, ButtonPressMask
  473.         | PointerMotionMask | LeaveWindowMask, FsflatMouseEvent,
  474.         newWindow->surroundingWindow);
  475.     /*
  476.      * Select these key press events in the title subwindow, but
  477.      * pass the surrounding window to the handlers.
  478.      */
  479.     Sx_HandlerCreate(fsflatDisplay, newWindow->titleWindow, KeyPressMask,
  480.         FsflatEditDir, newWindow->surroundingWindow);
  481.  
  482.     /*
  483.      * Move this further up before various datastructures are created?
  484.      * Add dir to fsflat's list.  Use windowID to match this dir for this
  485.      * window.
  486.      */
  487.     if (!MonClient_AddDir(newWindow->dir, newWindow->surroundingWindow)) {
  488.     /* What should I do here? */
  489.     Sx_Panic(fsflatDisplay,
  490.         "File system monitor failed in FsflatCreate().");
  491.     }
  492.  
  493.     return newWindow;
  494. }
  495.  
  496.  
  497. /*
  498.  *----------------------------------------------------------------------
  499.  *
  500.  * FsflatInit --
  501.  *
  502.  *    Initialize a new flat display.
  503.  *
  504.  * Results:
  505.  *    None.
  506.  *
  507.  * Side effects:
  508.  *    Lots.
  509.  *
  510.  *----------------------------------------------------------------------
  511.  */
  512. void
  513. FsflatInit(aWindow)
  514.     FsflatWindow    *aWindow;    /* info for this instance of display */
  515. {
  516.     XColor    cursorForeground;
  517.     XColor    cursorBackground;
  518.     Pixmap    source;
  519.  
  520.     cursorForeground.pixel = aWindow->background;
  521.     cursorBackground.pixel = aWindow->foreground;
  522.     XQueryColor(fsflatDisplay, DefaultColormap(fsflatDisplay,
  523.         DefaultScreen(fsflatDisplay)), &cursorForeground);
  524.     XQueryColor(fsflatDisplay, DefaultColormap(fsflatDisplay,
  525.         DefaultScreen(fsflatDisplay)), &cursorBackground);
  526.     if (flatCursor == -1) {
  527.     source = XCreateBitmapFromData(fsflatDisplay,
  528.         DefaultRootWindow(fsflatDisplay), flatCursor_bits,
  529.         flatCursor_width, flatCursor_height);
  530.     flatCursor = XCreatePixmapCursor(fsflatDisplay, source, None,
  531.         &cursorBackground, &cursorForeground, flatCursor_x_hot,
  532.         flatCursor_y_hot);
  533.     XFreePixmap(fsflatDisplay, source);
  534.     }
  535.     /* We'll need the cursor later - don't free it */
  536.     XDefineCursor(fsflatDisplay, aWindow->displayWindow, flatCursor);
  537.  
  538.     /*
  539.      * When work is being done, the cursor changes to the "wait" cursor.
  540.      */
  541.     if (waitCursor == -1) {
  542.     source = XCreateBitmapFromData(fsflatDisplay,
  543.         DefaultRootWindow(fsflatDisplay), waitCursor_bits,
  544.         waitCursor_width, waitCursor_height);
  545.     waitCursor = XCreatePixmapCursor(fsflatDisplay, source, None,
  546.         &cursorBackground, &cursorForeground, waitCursor_x_hot,
  547.         waitCursor_y_hot);
  548.     XFreePixmap(fsflatDisplay, source);
  549.     }
  550.     {
  551.     Window    dummy1;
  552.     int    x, y, width, height, border_width, dummy2;
  553.  
  554.     if (XGetGeometry(fsflatDisplay, aWindow->displayWindow, &dummy1,
  555.         &x, &y, &width, &height, &border_width, &dummy2) == 0) {
  556.         Sx_Panic(fsflatDisplay, "Couldn't get display window geometry.");
  557.     }
  558.     FsflatSetWindowAndRowInfo(aWindow, height, width);
  559.     }
  560.  
  561.     /* initialize data structures */
  562.     aWindow->displayInstructions = 0;
  563.     aWindow->sortingInstructions = 0;
  564.     aWindow->maxNameLength = 0;        /* longest length name */
  565.     aWindow->maxEntryWidth = 0;        /* longest entry */
  566.     aWindow->numElements = -1;        /* >= 0 means already initialized */
  567.     aWindow->totalDisplayEntries = 0;
  568.     /* numRows and rowHeight set above */
  569.     aWindow->firstElement = aWindow->lastElement = -1;
  570.     /* 8 columns is probably more than plenty to start out with. */
  571.     aWindow->columns = (FsflatColumn *) malloc(8 * sizeof (FsflatColumn));
  572.     aWindow->maxColumns = 8;
  573.     aWindow->usedCol = -1;
  574.     if (fsflatResizeP) {
  575.     aWindow->resizeP = TRUE;
  576.     } else {
  577.     aWindow->resizeP = FALSE;
  578.     }
  579.     if (fsflatPickSizeP) {
  580.     aWindow->pickSizeP = TRUE;
  581.     } else {
  582.     aWindow->pickSizeP = FALSE;
  583.     }
  584.     if (fsflatShowEmptyGroupsP) {
  585.     aWindow->hideEmptyGroupsP = FALSE;
  586.     } else {
  587.     aWindow->hideEmptyGroupsP = TRUE;
  588.     }
  589.     aWindow->groupList = NULL;
  590.     aWindow->selectionList = NULL;
  591.     /* create command bindings table and tcl interpreter. */
  592.     FsflatCmdTableInit(&(aWindow->cmdTable), &(aWindow->interp),
  593.         commands, (ClientData) aWindow);
  594.  
  595.     FsflatSourceConfig(aWindow);
  596.  
  597.     /* figure initial size */
  598.     if (aWindow->pickSizeP) {
  599.     aWindow->pickSizeP = FALSE;        /* only the first time */
  600.     /* This next will cause the surrounding window to change shape */
  601.     FigureWindowSize(aWindow, GetMaxEntryWidth(aWindow));
  602.     }
  603.     /* map surrounding  window */
  604.     XMapWindow(fsflatDisplay, aWindow->surroundingWindow);
  605.  
  606.     Sx_HandlerCreate(fsflatDisplay, aWindow->displayWindow,
  607.         ExposureMask | StructureNotifyMask,
  608.         FsflatHandleDrawingEvent, (ClientData) aWindow);
  609.     Sx_HandlerCreate(fsflatDisplay, aWindow->displayWindow, KeyPressMask,
  610.         FsflatKeyProc, (ClientData) aWindow);
  611.     Sx_HandlerCreate(fsflatDisplay, aWindow->menuBar, EnterWindowMask,
  612.         FsflatMenuEntryProc, (ClientData) aWindow);
  613.  
  614.     return;
  615. }
  616.  
  617.  
  618. /*
  619.  *----------------------------------------------------------------------
  620.  *
  621.  * FsflatSetPositions --
  622.  *
  623.  *    Figure out and set the coordinates of things to display.
  624.  *    This means sticking things in columns and determining when
  625.  *    the display would be filled up.
  626.  *
  627.  * Results:
  628.  *    None.
  629.  *
  630.  * Side effects:
  631.  *    The coordinates change.  A new column or so may be allocated.
  632.  *
  633.  *----------------------------------------------------------------------
  634.  */
  635. void
  636. FsflatSetPositions(aWindow)
  637.     FsflatWindow    *aWindow;
  638. {
  639.     FsflatGroup        *tmpGroupPtr = NULL;
  640.     FsflatFile        *tmpFilePtr = NULL;
  641.     FsflatColumn    *newColumns;
  642.     Boolean        spaceP = FALSE;
  643.     int            numCols;
  644.     int            i;
  645.     int            maxEntryWidth;
  646.     int            numMappedHeaders = 0;    /* Use at end for ignoring
  647.                          * extra expose events. */
  648.  
  649. #ifdef SCROLL_DEBUG
  650.     fprintf(stderr, "Entered FsflatSetPositions:\n");
  651.     fprintf(stderr, "\tfirstElement is %d\n",
  652.         aWindow->firstElement);
  653.     fprintf(stderr, "\tlastElement is %d\n",
  654.         aWindow->lastElement);
  655.     fprintf(stderr, "\tnumElements is %d\n",
  656.         aWindow->numElements);
  657.     fprintf(stderr, "\tcolumns used is %d\n",
  658.         aWindow->usedCol + 1);
  659. #endif SCROLL_DEBUG
  660.  
  661.     if (aWindow->firstElement <= 0) {
  662.     sprintf(fsflatErrorMsg,
  663.         "Entered FsflatSetPositions with firstElement = %d",
  664.         aWindow->firstElement);
  665.     Sx_Panic(fsflatDisplay, fsflatErrorMsg);
  666.     }
  667.     /*
  668.      * Avoid exposure events from creating and resizing windows below.  The
  669.      * window will be remapped later causing FsflatRedraw() to be called.
  670.      */
  671.     XUnmapWindow(fsflatDisplay, aWindow->displayWindow);
  672.  
  673.     maxEntryWidth = GetMaxEntryWidth(aWindow);
  674.     if (aWindow->resizeP) {
  675.     FigureWindowSize(aWindow, maxEntryWidth);
  676.     }
  677.     GetColumnWidthInfo(aWindow, maxEntryWidth, &(aWindow->columnWidth),
  678.         &numCols);
  679. #ifdef SCROLL_DEBUG
  680.     fprintf(stderr, "Number of columns to use is %d\n", numCols);
  681. #endif SCROLL_DEBUG
  682.  
  683.     /* do we need to allocate more columns? */
  684.     if (numCols > aWindow->maxColumns) {
  685.     newColumns = (FsflatColumn *)
  686.         malloc(aWindow->maxColumns * 2 * sizeof (FsflatColumn));
  687.     for (i = 0; i < aWindow->maxColumns; i++) {
  688.         newColumns[i] = aWindow->columns[i];
  689.     }
  690.     free(aWindow->columns);
  691.     aWindow->columns = newColumns;
  692.     aWindow->maxColumns *= 2;
  693.     }
  694.  
  695.     /* get to the first one to display */
  696.     i = 0;
  697.     aWindow->lastElement = 0;
  698.     for (tmpGroupPtr = aWindow->groupList; tmpGroupPtr != NULL;
  699.         tmpGroupPtr = tmpGroupPtr->nextPtr) {
  700.     /*
  701.      * Check if we've hit the right element to start displaying at.  If
  702.      * so, then check that either it's okay to display headers for empty
  703.      * groups, or else this isn't an empty group.
  704.      */
  705.     if ((i + 1 == aWindow->firstElement) && (!aWindow->hideEmptyGroupsP ||
  706.         tmpGroupPtr->fileList != NULL)) {
  707.         break;
  708.     }
  709.     tmpGroupPtr->myColumn = -1;
  710.     tmpGroupPtr->x = tmpGroupPtr->y = -1;
  711.     if (tmpGroupPtr->headerWindow != UNINITIALIZED) {
  712.         XUnmapWindow(fsflatDisplay, tmpGroupPtr->headerWindow);
  713.     }
  714.     /* only increment if this was a visible header */
  715.     if (!aWindow->hideEmptyGroupsP || tmpGroupPtr->fileList != NULL) {
  716.         i++;
  717.     }
  718.     for (tmpFilePtr = tmpGroupPtr->fileList; tmpFilePtr != NULL;
  719.         tmpFilePtr = tmpFilePtr->nextPtr) {
  720.         if (i + 1 == aWindow->firstElement) {
  721.         break;
  722.         } else {
  723.         tmpFilePtr->x = tmpFilePtr->y = -1;
  724.         tmpFilePtr->myColumn = -1;
  725.         }
  726.         i++;
  727.     }
  728.     if (tmpFilePtr != NULL) {
  729.         break;    /* we found it */
  730.     }
  731.     if (i+1 == aWindow->firstElement) {
  732.         /*
  733.          * The next thing we would display is a space followed by a
  734.          * group header, unless the group is an empty group and we aren't
  735.          * supposed to be displaying empty groups...
  736.          */
  737.         if (!aWindow->hideEmptyGroupsP || (tmpGroupPtr->nextPtr != NULL &&
  738.             tmpGroupPtr->nextPtr->fileList != NULL)) {
  739.         spaceP = TRUE;
  740.         tmpGroupPtr = tmpGroupPtr->nextPtr;
  741.         break;
  742.         }
  743.     }
  744.     /* only increment if this would be a space after a visible header */
  745.     if (!aWindow->hideEmptyGroupsP || tmpGroupPtr->fileList != NULL) {
  746.         i++;
  747.     }
  748.     }
  749.     if (tmpGroupPtr == NULL) {        /* all groups were empty, no display */
  750.     goto finished;
  751.     }
  752.     /* We've figured out what to start displaying */
  753.  
  754.     /* Now fill in the columns */
  755.     for (aWindow->usedCol = 0; aWindow->usedCol < numCols; aWindow->usedCol++) {
  756.     aWindow->columns[aWindow->usedCol].x =
  757.         aWindow->usedCol * aWindow->columnWidth;
  758.  
  759.     for (i = 0; i < aWindow->numRows; i++) {
  760.         if (spaceP == TRUE) {
  761.         spaceP = FALSE;
  762.         continue;
  763.         }
  764.         /*
  765.          * If tmpFilePtr is NULL, we have come to a new group header.
  766.          */
  767.         if (tmpFilePtr == NULL) {
  768.         /* set tmpFilePtr to fileList for this group. */
  769.  
  770.         tmpFilePtr = tmpGroupPtr->fileList;
  771.         if (aWindow->hideEmptyGroupsP && tmpFilePtr == NULL) {
  772.             if (tmpGroupPtr->headerWindow != UNINITIALIZED) {
  773.             XUnmapWindow(fsflatDisplay, tmpGroupPtr->headerWindow);
  774.             }
  775.             tmpGroupPtr = tmpGroupPtr->nextPtr;
  776.             i--;    /* so that i is the same next iteration */
  777.             if (tmpGroupPtr == NULL) {    /* end of groups */
  778.             goto finished;
  779.             }
  780.             continue;
  781.         }
  782.         tmpGroupPtr->myColumn = aWindow->usedCol;
  783.         tmpGroupPtr->x = aWindow->columns[aWindow->usedCol].x;
  784.         tmpGroupPtr->y = i * aWindow->rowHeight;
  785.         strcpy(tmpGroupPtr->editHeader, tmpGroupPtr->rule);
  786.         if (tmpGroupPtr->headerWindow == UNINITIALIZED) {
  787.             /* Need to create a header window */
  788. /* necessary? */    tmpGroupPtr->entry_width = aWindow->columnWidth;
  789.             tmpGroupPtr->entry_x = tmpGroupPtr->x;
  790.             tmpGroupPtr->entry_y = tmpGroupPtr->y;
  791.             /*
  792.              * If it's the first column, then start it one pixel
  793.              * to the left, so that borders overlap.
  794.              */
  795.             if (tmpGroupPtr->myColumn > 0) {
  796.             tmpGroupPtr->headerWindow =
  797.                 Sx_EntryCreate(fsflatDisplay,
  798.                 aWindow->displayWindow,
  799.                 tmpGroupPtr->x, tmpGroupPtr->y - 1,
  800.                 aWindow->columnWidth - 1,
  801.                 aWindow->rowHeight - 1, 1, NULL,
  802.                 aWindow->fontPtr, aWindow->entryForeground,
  803.                 aWindow->entryBackground,
  804.                 tmpGroupPtr->editHeader,
  805.                 sizeof (tmpGroupPtr->editHeader));
  806.             } else {
  807.             tmpGroupPtr->headerWindow =
  808.                 Sx_EntryCreate(fsflatDisplay,
  809.                 aWindow->displayWindow,
  810.                 tmpGroupPtr->x - 1, tmpGroupPtr->y - 1,
  811.                 aWindow->columnWidth,
  812.                 aWindow->rowHeight - 1, 1, NULL,
  813.                 aWindow->fontPtr, aWindow->entryForeground,
  814.                 aWindow->entryBackground,
  815.                 tmpGroupPtr->editHeader,
  816.                 sizeof (tmpGroupPtr->editHeader));
  817.             }
  818.             if (tmpGroupPtr->headerWindow == 0) {
  819.             Sx_Panic(fsflatDisplay,
  820.                 "You've run out of windows?!  Farewell!");
  821.             }
  822.             XSaveContext(fsflatDisplay, tmpGroupPtr->headerWindow,
  823.                 fsflatWindowContext, (caddr_t) aWindow);
  824.             XSaveContext(fsflatDisplay, tmpGroupPtr->headerWindow,
  825.                 fsflatGroupWindowContext, (caddr_t) tmpGroupPtr);
  826.             Sx_HandlerCreate(fsflatDisplay,
  827.                 tmpGroupPtr->headerWindow, KeyPressMask,
  828.                 FsflatEditRule, tmpGroupPtr->headerWindow);
  829.         } else {
  830.             /* is the window in a new place? */
  831.             if (tmpGroupPtr->entry_x != tmpGroupPtr->x ||
  832.                 tmpGroupPtr->entry_y != tmpGroupPtr->y ||
  833.                 tmpGroupPtr->entry_width !=
  834.                 aWindow->columnWidth) {
  835.             XWindowChanges    changes;
  836.  
  837.             tmpGroupPtr->entry_x = tmpGroupPtr->x;
  838.             tmpGroupPtr->entry_y = tmpGroupPtr->y;
  839.             tmpGroupPtr->entry_width = aWindow->columnWidth;
  840.             if (tmpGroupPtr->myColumn > 0) {
  841.                 changes.x = tmpGroupPtr->x;
  842.                 changes.y = tmpGroupPtr->y - 1;
  843.                 changes.width = aWindow->columnWidth - 1;
  844.                 changes.height = aWindow->rowHeight - 1;
  845.             } else {
  846.                 changes.x = tmpGroupPtr->x - 1;
  847.                 changes.y = tmpGroupPtr->y - 1;
  848.                 changes.width = aWindow->columnWidth;
  849.                 changes.height = aWindow->rowHeight - 1;
  850.             }
  851.             XConfigureWindow(fsflatDisplay,
  852.                 tmpGroupPtr->headerWindow,
  853.                 CWX | CWY | CWWidth | CWHeight, &changes);
  854.             }
  855.         }
  856.         /* in case it wasn't visible last time */
  857.         XMapWindow(fsflatDisplay, tmpGroupPtr->headerWindow);
  858.         numMappedHeaders++;    /* another header window mapped */
  859.         /*
  860.          * If fileList is NULL for this group, move to next group.
  861.          * If this new group isn't null, it means we need another space.
  862.          * Otherwise, we're finished with all the groups.
  863.          */
  864.         if (tmpFilePtr != NULL) {
  865.             continue;
  866.         }
  867.         /*
  868.           * The group's fileList is null, move on to new group.
  869.          * We can only get here with a null fileList if
  870.          * aWindow->hideEmptyGroupsP is FALSE.
  871.          */
  872.         tmpGroupPtr = tmpGroupPtr->nextPtr;
  873.         if (tmpGroupPtr == NULL) {
  874.             /* end of groups */
  875.             aWindow->lastElement = i + 1;
  876.             break;
  877.         }
  878.         /* leave tmpFilePtr NULL so that we know we're between groups */
  879.         spaceP = TRUE;
  880.         continue;
  881.         }
  882.         /* tmpFilePtr was not NULL, so set positions for the file name. */
  883.         tmpFilePtr->x = aWindow->columns[aWindow->usedCol].x;
  884.         tmpFilePtr->y = i * aWindow->rowHeight;
  885.         tmpFilePtr->myColumn = aWindow->usedCol;
  886.  
  887.         /* move on to next file */
  888.         tmpFilePtr = tmpFilePtr->nextPtr;
  889.         if (tmpFilePtr == NULL) {
  890.         /* end of group */
  891.         tmpGroupPtr = tmpGroupPtr->nextPtr;
  892.         if (tmpGroupPtr == NULL) {
  893.             /* end of groups */
  894.             aWindow->lastElement = i + 1;
  895.             break;
  896.         }
  897.         spaceP = TRUE;
  898.         }
  899.         continue;
  900.     }
  901.  
  902.     /* We're at the end of a column */
  903.     if (tmpGroupPtr == NULL) {
  904.         /* end of groups */
  905.         aWindow->usedCol++;        /* so it ends one bigger than used */
  906.         break;
  907.     }
  908.     }
  909.  
  910.     aWindow->usedCol--;        /* loop leaves it one too big */
  911. finished:
  912.  
  913.     /* mark the rest as not visible */
  914.     for ( ; tmpGroupPtr != NULL; tmpGroupPtr = tmpGroupPtr->nextPtr) {
  915.     /* If we stopped at a header, mark it as not visible */
  916.     if (tmpFilePtr == NULL) {
  917.         tmpGroupPtr->myColumn = -1;
  918.         tmpGroupPtr->x = tmpGroupPtr->y = -1;
  919.         if (tmpGroupPtr->headerWindow != UNINITIALIZED) {
  920.         XUnmapWindow(fsflatDisplay, tmpGroupPtr->headerWindow);
  921.         }
  922.         tmpFilePtr = tmpGroupPtr->fileList;
  923.     }
  924.  
  925.     for ( ; tmpFilePtr != NULL; tmpFilePtr = tmpFilePtr->nextPtr) {
  926.         tmpFilePtr->x = tmpFilePtr->y = -1;
  927.         tmpFilePtr->myColumn = -1;
  928.     }
  929.     }
  930.  
  931.     /* The number of the last element visible -- includes spaces and headers */
  932.     if (aWindow->lastElement == 0) {
  933.     aWindow->lastElement = aWindow->firstElement - 1 +
  934.         ((aWindow->usedCol + 1) * aWindow->numRows);
  935.     } else {
  936.     /* We're partway into a column, add on columns up to this one */
  937.     aWindow->lastElement += aWindow->firstElement - 1 +
  938.         (aWindow->usedCol * aWindow->numRows);
  939.     }
  940.  
  941.     /* Get rid of extraneous redraw events from mapping(?) Sx entry windows. */
  942.     for (i = 0; i < numMappedHeaders; i++) {
  943.     XEvent    tossEvent;    /* dispose of this extra event */
  944.  
  945.     XCheckWindowEvent(fsflatDisplay, aWindow->displayWindow, ExposureMask,
  946.         &tossEvent);
  947.     }
  948.  
  949.     /* This causes FsflatRedraw() to be called, so the whole thing appears. */
  950.     XMapWindow(fsflatDisplay, aWindow->displayWindow);
  951.  
  952. #ifdef SCROLL_DEBUG
  953.     fprintf(stderr, "At end of FsflatSetPositions:\n");
  954.     fprintf(stderr, "\tfirstElement is %d\n",
  955.         aWindow->firstElement);
  956.     fprintf(stderr, "\tlastElement is %d\n",
  957.         aWindow->lastElement);
  958.     fprintf(stderr, "\tnumElements is %d\n",
  959.         aWindow->numElements);
  960.     fprintf(stderr, "\tnumGroups is %d\n", aWindow->numGroups);
  961.     fprintf(stderr, "\tnumRows is %d\n", aWindow->numRows);
  962.     fprintf(stderr, "\tcolumns used is %d\n",
  963.         aWindow->usedCol + 1);
  964. #endif SCROLL_DEBUG
  965.  
  966.     return;
  967. }
  968.  
  969.  
  970. /*
  971.  *----------------------------------------------------------------------
  972.  *
  973.  * FsflatRedraw --
  974.  *
  975.  *    Redraw display with positions already set.
  976.  *
  977.  * Results:
  978.  *    None.
  979.  *
  980.  * Side effects:
  981.  *    The display is redrawn.
  982.  *
  983.  *----------------------------------------------------------------------
  984.  */
  985. void
  986. FsflatRedraw(aWindow)
  987.     FsflatWindow    *aWindow;
  988. {
  989.     int    i;
  990.     FsflatGroup    *tmpGroupPtr = NULL;
  991.     FsflatFile    *tmpPtr = NULL;
  992.     float    top, bottom;
  993.     char    fields[MAXNAMLEN + (3 * 26) + 11];    /* space allocation
  994.                              * described below */
  995.     char    sorting[50];
  996.     Boolean    somethingDrawnP = FALSE;
  997.  
  998.     strcpy(fields, "Filename");
  999.     for (i = 0; i < aWindow->maxNameLength - strlen("Filename"); i++) {
  1000.     /* Very wasteful... */
  1001.     strcat(fields, " ");
  1002.     }
  1003.     if (aWindow->displayInstructions & FSFLAT_ATIME_FIELD) {
  1004.     /* 24 chars needed for time, plus 2 spaces == 26 */
  1005.     strcat(fields, "  AccessTime              ");
  1006.     }
  1007.     if (aWindow->displayInstructions & FSFLAT_MTIME_FIELD) {
  1008.     /* 24 chars needed for time, plus 2 spaces == 26 */
  1009.     strcat(fields, "  DataModifyTime          ");
  1010.     }
  1011.     if (aWindow->displayInstructions & FSFLAT_DTIME_FIELD) {
  1012.     /* 24 chars needed for time, plus 2 spaces == 26 */
  1013.     /*
  1014.      * This is one of the few places where Descriptor isn't spelled out -
  1015.      * for space considerations.
  1016.      */
  1017.     strcat(fields, "  DescModifyTime          ");
  1018.     }
  1019.     if (aWindow->displayInstructions & FSFLAT_SIZE_FIELD) {
  1020.     /* 9 chars needed for size, plus 2 spaces == 11 */
  1021.     strcat(fields, "      Bytes");
  1022.     }
  1023.  
  1024.     strcpy(sorting, "Sorted by:  ");
  1025.     if (aWindow->sortingInstructions & FSFLAT_ALPHA_SORT) {
  1026.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  1027.         strcat(sorting, "Reverse Alphabet");
  1028.     } else {
  1029.         strcat(sorting, "Alphabet"); }
  1030.     }
  1031.     if (aWindow->sortingInstructions & FSFLAT_ATIME_SORT) {
  1032.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  1033.         strcat(sorting, "Reverse AccessTime");
  1034.     } else {
  1035.         strcat(sorting, "AccessTime");
  1036.     }
  1037.     }
  1038.     if (aWindow->sortingInstructions & FSFLAT_MTIME_SORT) {
  1039.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  1040.         strcat(sorting, "Reverse DataModifyTime");
  1041.     } else {
  1042.         strcat(sorting, "DataModifyTime");
  1043.     }
  1044.     }
  1045.     if (aWindow->sortingInstructions & FSFLAT_DTIME_SORT) {
  1046.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  1047.         strcat(sorting, "Reverse DescriptorModifyTime");
  1048.     } else {
  1049.         strcat(sorting, "DescriptorModifyTime");
  1050.     }
  1051.     }
  1052.     if (aWindow->sortingInstructions & FSFLAT_SIZE_SORT) {
  1053.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  1054.         strcat(sorting, "Reverse Size");
  1055.     } else {
  1056.         strcat(sorting, "Size");
  1057.     }
  1058.     }
  1059.  
  1060. #ifdef SCROLL_DEBUG
  1061.     fprintf(stderr, "Entered FsflatRedraw:\n");
  1062.     fprintf(stderr, "\tfirstElement is %d\n",
  1063.         aWindow->firstElement);
  1064.     fprintf(stderr, "\tlastElement is %d\n",
  1065.         aWindow->lastElement);
  1066.     fprintf(stderr, "\tnumElements is %d\n",
  1067.         aWindow->numElements);
  1068.     fprintf(stderr, "\tnumGroups is %d\n", aWindow->numGroups);
  1069. #endif SCROLL_DEBUG
  1070.  
  1071.     XClearArea(fsflatDisplay, aWindow->displayWindow, 0, 0, 0, 0, False);
  1072.  
  1073.     for (tmpGroupPtr = aWindow->groupList;
  1074.         tmpGroupPtr != NULL; tmpGroupPtr = tmpGroupPtr->nextPtr) {
  1075.     for (tmpPtr = tmpGroupPtr->fileList;
  1076.         tmpPtr != NULL; tmpPtr = tmpPtr->nextPtr) {
  1077.         FsflatRedrawFile(aWindow, tmpPtr);
  1078.         somethingDrawnP = TRUE;
  1079.     }
  1080.     }
  1081.     /*
  1082.      * Now draw the column dividers.
  1083.      */
  1084.     if (somethingDrawnP) {
  1085.     for (i = 1; i <= aWindow->usedCol; i++) {
  1086.         XDrawLine(fsflatDisplay, aWindow->displayWindow,
  1087.             aWindow->textGc,
  1088.             aWindow->columns[i].x, 0,
  1089.             aWindow->columns[i].x, aWindow->windowHeight);
  1090.     }
  1091.     }
  1092.     /*
  1093.      * Now set the scroll bar to match what will be displayed.
  1094.      */
  1095.     if (aWindow->numRows == 0) {
  1096.     top = 0.0;
  1097.     bottom = 1.0;
  1098.     } else {
  1099.     /*
  1100.      * First (last) entry divided by number of entries required.  (This
  1101.      * includes any displayed spaces and groups.)
  1102.      */
  1103.     top = ((float) aWindow->firstElement - 1) /
  1104.         ((float) aWindow->totalDisplayEntries);
  1105.     bottom = ((float) aWindow->lastElement) /
  1106.         ((float) aWindow->totalDisplayEntries);
  1107.     }
  1108. #ifdef SCROLL_DEBUG
  1109.     fprintf(stderr, "At end of FsflatRedraw:\n");
  1110.     fprintf(stderr, "\ttop is %f\n", top);
  1111.     fprintf(stderr, "\tbottom is %f\n", bottom);
  1112.     fprintf(stderr, "\tcalling SetRange.\n");
  1113. #endif SCROLL_DEBUG
  1114.  
  1115.     Sx_ScrollbarSetRange(fsflatDisplay, aWindow->scrollWindow, top, bottom);
  1116.     Sx_TitleMake(fsflatDisplay, aWindow->sortWindow, aWindow->fontPtr,
  1117.         aWindow->sortForeground, aWindow->sortBackground,
  1118.         aWindow->sortBackground, sorting, NULL, NULL);
  1119.     Sx_TitleMake(fsflatDisplay, aWindow->fieldsWindow, aWindow->fontPtr,
  1120.         aWindow->fieldsForeground, aWindow->fieldsBackground,
  1121.         aWindow->fieldsBackground, fields, NULL, NULL);
  1122.  
  1123.     return;
  1124. }
  1125.  
  1126.  
  1127.  
  1128. /*
  1129.  *----------------------------------------------------------------------
  1130.  *
  1131.  * FsflatRedrawFile --
  1132.  *
  1133.  *    Redraw a file entry.  Highlight with a box, or indicate that it is
  1134.  *    selected, if required.
  1135.  *
  1136.  * Results:
  1137.  *    None.
  1138.  *
  1139.  * Side effects:
  1140.  *    The file entry is redisplayed.
  1141.  *
  1142.  *----------------------------------------------------------------------
  1143.  */
  1144. void
  1145. FsflatRedrawFile(aWindow, filePtr)
  1146.     FsflatWindow    *aWindow;
  1147.     FsflatFile        *filePtr;
  1148. {
  1149.     char    *space = NULL;
  1150.     int        secondFieldStart;
  1151.     int        ascent;
  1152.     int        lbearing;    /* to indent string enough that we don't
  1153.                  * draw a box over its first char */
  1154.  
  1155.     if (filePtr->x == -1) {        /* is it visible? */
  1156.     return;
  1157.     }
  1158.     ascent = aWindow->fontPtr->ascent;
  1159.     lbearing =  -4;
  1160.     if ((aWindow->displayInstructions & ~FSFLAT_NAME_FIELD) != 0) {
  1161.     space = (char *) malloc(aWindow->maxEntryWidth + 1 -
  1162.         aWindow->maxNameLength);
  1163.     space[0] = '\0';
  1164.     FsflatGetFileFields(aWindow, filePtr, &space);
  1165.     }
  1166.  
  1167.     secondFieldStart =
  1168.         FSFLAT_CHAR_TO_WIDTH(aWindow->maxNameLength + 2, aWindow->fontPtr);
  1169.     if (filePtr->selectedP || filePtr->myGroupPtr->selectedP) {
  1170.     /* should highlight */
  1171.     XDrawImageString(fsflatDisplay, aWindow->displayWindow,
  1172.         aWindow->reverseGc, filePtr->x + -lbearing + 1,
  1173.         filePtr->y + ascent, filePtr->name, strlen(filePtr->name));
  1174.     if (space != NULL) {
  1175.         if (filePtr->lineP) {
  1176.         XDrawImageString(fsflatDisplay, aWindow->displayWindow,
  1177.             aWindow->reverseGc,
  1178.             filePtr->x + secondFieldStart,
  1179.             filePtr->y + ascent, space, strlen(space));
  1180.         } else {
  1181.         XDrawImageString(fsflatDisplay, aWindow->displayWindow,
  1182.             aWindow->reverseGc,
  1183.             filePtr->x + secondFieldStart,
  1184.             filePtr->y + ascent, space, strlen(space));
  1185.         }
  1186.     }
  1187.     } else {
  1188.     XDrawImageString(fsflatDisplay, aWindow->displayWindow, aWindow->textGc,
  1189.         filePtr->x + -lbearing + 1, filePtr->y + ascent, filePtr->name,
  1190.         strlen(filePtr->name)); 
  1191.     if (space != NULL) {
  1192.         XDrawImageString(fsflatDisplay, aWindow->displayWindow,
  1193.             aWindow->textGc, filePtr->x + secondFieldStart,
  1194.             filePtr->y + ascent, space, strlen(space));
  1195.     }
  1196.     }
  1197.  
  1198.     /* draw or undraw a box around it */
  1199.     {
  1200.     XPoint    vlist[5];
  1201.  
  1202.     vlist[0].x = filePtr->x + 1;
  1203.     vlist[0].y = filePtr->y + aWindow->rowHeight;
  1204.  
  1205.     /*
  1206.      * To make up for indentation of string by -lbearing amount.
  1207.      */
  1208.     vlist[1].x = -lbearing +
  1209.         FSFLAT_CHAR_TO_WIDTH(aWindow->maxNameLength, aWindow->fontPtr);
  1210.     vlist[1].y = 0;
  1211.  
  1212.     vlist[2].x = 0;
  1213.     vlist[2].y = -(aWindow->rowHeight);
  1214.  
  1215.     vlist[3].x = -(vlist[1].x);
  1216.     vlist[3].y = 0;
  1217.  
  1218.     /* should be equal to first point - if not, make all rel. to origin. */
  1219.     vlist[4].x = 0;
  1220.     vlist[4].y = -(vlist[2].y);
  1221.  
  1222.     if (filePtr->highlightP) {
  1223.         /* should be selectionGc */
  1224.         XDrawLines(fsflatDisplay, aWindow->displayWindow,
  1225.             aWindow->textGc, vlist, 5, CoordModePrevious);
  1226.     } else {
  1227.         XDrawLines(fsflatDisplay, aWindow->displayWindow,
  1228.             aWindow->reverseGc, vlist, 5, CoordModePrevious);
  1229.     }
  1230.     }
  1231.     if (space != NULL) {
  1232.     free(space);
  1233.     }
  1234.  
  1235.     return;
  1236. }
  1237.  
  1238.  
  1239. /*
  1240.  *----------------------------------------------------------------------
  1241.  *
  1242.  * FsflatGetFileFields --
  1243.  *
  1244.  *    Get the additional fields to display for a file entry beyond the
  1245.  *    file name.
  1246.  *    If *buf is null, then allocate space for the string to return.
  1247.  *    Otherwise copy the return value into *buf.
  1248.  *
  1249.  * Results:
  1250.  *    None.
  1251.  *
  1252.  * Side effects:
  1253.  *    The file entry is redisplayed.
  1254.  *
  1255.  *----------------------------------------------------------------------
  1256.  */
  1257. void
  1258. FsflatGetFileFields(aWindow, filePtr, buf)
  1259.     FsflatWindow    *aWindow;
  1260.     FsflatFile        *filePtr;
  1261.     char        **buf;
  1262. {
  1263.     char    timeBuf[26];    /* 26 chars according to ctime man page */
  1264.     char    intBuf[CVT_INT_BUF_SIZE + 1]; /* const defined in my .h file */
  1265.     int        i;
  1266.     char    *space;
  1267.  
  1268.     /* What to do here? */
  1269.     if (*buf == NULL) {
  1270.     *buf = (char *) malloc(aWindow->maxEntryWidth + 1 -
  1271.         aWindow->maxNameLength);
  1272.     *buf[0] = '\0';
  1273.     }
  1274.     space = *buf;
  1275.     /* Any fields except for name? */
  1276.     if (!(aWindow->displayInstructions & (~FSFLAT_NAME_FIELD))) {
  1277.     /* Could free up space from attrPtr field here, if I want. */
  1278.     return;
  1279.     }
  1280.     if (filePtr->attrPtr == NULL) {
  1281.     filePtr->attrPtr = (struct stat *) malloc(sizeof (struct stat));
  1282.     if (lstat(filePtr->name, filePtr->attrPtr)
  1283.         != 0) {
  1284.         sprintf(fsflatErrorMsg, "%s %s.  %s.",
  1285.             "Couldn't get attributes for file",
  1286.             filePtr->name,  "The file may no longer exist");
  1287.         Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  1288.             fsflatErrorMsg, NULL, TRUE, "Continue",
  1289.             (char *) NULL);
  1290.         bzero(filePtr->attrPtr, sizeof (struct    stat)); 
  1291.         strcat(space, "  X  ");
  1292.         return;
  1293.     }
  1294.     }
  1295.     if (aWindow->displayInstructions & FSFLAT_ATIME_FIELD) {
  1296.     /* 24 chars needed for time, plus 2 spaces == 26 */
  1297.     strcpy(timeBuf, ctime(&(filePtr->attrPtr->st_atime)));
  1298.     /* wasteful to do twice, I suppose */
  1299.     if (index(timeBuf, '\n') != NULL) {
  1300.         *(index(timeBuf, '\n')) = '\0';
  1301.     }
  1302.     strcat(space, timeBuf);
  1303.     strcat(space, "  ");
  1304.     }
  1305.     if (aWindow->displayInstructions & FSFLAT_MTIME_FIELD) {
  1306.     /* 24 chars needed for time, plus 2 spaces */
  1307.     strcpy(timeBuf, ctime(&(filePtr->attrPtr->st_mtime)));
  1308.     /* wasteful to do twice, I suppose */
  1309.     if (index(timeBuf, '\n') != NULL) {
  1310.         *(index(timeBuf, '\n')) = '\0';
  1311.     }
  1312.     strcat(space, timeBuf);
  1313.     strcat(space, "  ");
  1314.     }
  1315.     if (aWindow->displayInstructions & FSFLAT_DTIME_FIELD) {
  1316.     /* 24 chars needed for time, plus 2 spaces */
  1317.     strcpy(timeBuf, ctime(&(filePtr->attrPtr->st_ctime)));
  1318.     /* wasteful to do twice, I suppose */
  1319.     if (index(timeBuf, '\n') != NULL) {
  1320.         *(index(timeBuf, '\n')) = '\0';
  1321.     }
  1322.     strcat(space, timeBuf);
  1323.     strcat(space, "  ");
  1324.     }
  1325.     if (aWindow->displayInstructions & FSFLAT_SIZE_FIELD) {
  1326.     /* 9 chars needed for size, plus 2 spaces */
  1327.     sprintf(intBuf, "%d", filePtr->attrPtr->st_size);
  1328.     for (i = 0; i < 9 - strlen(intBuf); i++) {
  1329.         strcat(space, " ");
  1330.     }
  1331.     strcat(space, intBuf);
  1332.     strcat(space, "  ");
  1333.     }
  1334. #ifdef NOTDEF
  1335.     if (aWindow->displayInstructions & FSFLAT_OTHERSTUFF_FIELD) {
  1336.     /* 9 chars needed for size, plus 2 spaces */
  1337.     }
  1338. #endif NOTDEF
  1339.  
  1340.     return;
  1341. }
  1342.  
  1343.  
  1344. /*
  1345.  *----------------------------------------------------------------------
  1346.  *
  1347.  * FsflatSetWindowAndRowInfo --
  1348.  *
  1349.  *    Given the dimensions of the window, calculate
  1350.  *    the height of rows and the number of usable rows in the window,
  1351.  *    and set these fields (and the window dimension fields) in the
  1352.  *    given FsflatWindow structure.  The row height calculation is
  1353.  *    made relative to the current font height specified in the fontPtr
  1354.  *    field of the FsflatWindow structure.
  1355.  *
  1356.  * Results:
  1357.  *    None.
  1358.  *
  1359.  * Side effects:
  1360.  *    The fields in the FsflatWindow structure that are set are
  1361.  *    the rowHeight, numRows, windowHeight and windowWidth fields.
  1362.  *
  1363.  *----------------------------------------------------------------------
  1364.  */
  1365. void
  1366. FsflatSetWindowAndRowInfo(aWindow, height, width)
  1367.     FsflatWindow    *aWindow;
  1368.     int            height, width;
  1369. {
  1370.     aWindow->windowHeight = height;
  1371.     aWindow->windowWidth = width;
  1372.     aWindow->rowHeight = aWindow->fontPtr->max_bounds.ascent +
  1373.         aWindow->fontPtr->max_bounds.descent + FSFLAT_ROW_SPACING;
  1374.     aWindow->numRows = aWindow->windowHeight / aWindow->rowHeight;
  1375.  
  1376.     return;
  1377. }
  1378.  
  1379.  
  1380.  
  1381. /*
  1382.  *----------------------------------------------------------------------
  1383.  *
  1384.  * FsflatRedrawGroup --
  1385.  *
  1386.  *    Not yet implemented.
  1387.  *
  1388.  * Results:
  1389.  *    None.
  1390.  *
  1391.  * Side effects:
  1392.  *    None.
  1393.  *
  1394.  *----------------------------------------------------------------------
  1395.  */
  1396. /*ARGSUSED*/
  1397. void
  1398. FsflatRedrawGroup(aWindow, groupPtr)
  1399.     FsflatWindow    *aWindow;
  1400.     FsflatGroup        *groupPtr;
  1401. {
  1402.     return;
  1403. }
  1404.  
  1405.  
  1406. /*
  1407.  *----------------------------------------------------------------------
  1408.  *
  1409.  * FsflatMapCoordsToFile --
  1410.  *
  1411.  *    Map the given coordinates to a file entry.  The mapping will work
  1412.  *    if the cursor is on the same line as a file entry.  It does not
  1413.  *    have to be directory over the file entry.
  1414.  *
  1415.  * Results:
  1416.  *    A pointer to the appropriate file entry, or NULL if there isn't
  1417.  *    one under the given coordinates.    
  1418.  *
  1419.  * Side effects:
  1420.  *    None.
  1421.  *
  1422.  *----------------------------------------------------------------------
  1423.  */
  1424. FsflatFile *
  1425. FsflatMapCoordsToFile(aWindow, x, y)
  1426.     FsflatWindow    *aWindow;
  1427.     int            x, y;
  1428. {
  1429.     FsflatGroup    *groupPtr;
  1430.     FsflatFile    *filePtr;
  1431.     int        ascent;
  1432.  
  1433.     ascent = aWindow->fontPtr->ascent;
  1434.     for (groupPtr = aWindow->groupList; groupPtr != NULL;
  1435.         groupPtr = groupPtr->nextPtr) {
  1436.     for (filePtr = groupPtr->fileList; filePtr != NULL;
  1437.         filePtr = filePtr->nextPtr) {
  1438.         if (filePtr->x == -1) {    /* off the display */
  1439.         continue;
  1440.         }
  1441.         if ((filePtr->x <= x && x <= filePtr->x + aWindow->columnWidth) &&
  1442.             (filePtr->y + ascent <= y && y <= filePtr->y + ascent +
  1443.             aWindow->rowHeight)) {
  1444.         return filePtr;
  1445.         }
  1446.     }
  1447.     }
  1448.  
  1449.     return NULL;
  1450. }
  1451.  
  1452.  
  1453. /*
  1454.  *----------------------------------------------------------------------
  1455.  *
  1456.  * FsflatMapCoordsToGroup --
  1457.  *
  1458.  *    Map the given coordinates to a group header.
  1459.  *
  1460.  * Results:
  1461.  *    A pointer to the appropriate group header, or NULL if there isn't
  1462.  *    one under the given coordinates.
  1463.  *
  1464.  * Side effects:
  1465.  *    None.
  1466.  *
  1467.  *----------------------------------------------------------------------
  1468.  */
  1469. FsflatGroup *
  1470. FsflatMapCoordsToGroup(aWindow, x, y)
  1471.     FsflatWindow    *aWindow;
  1472.     int            x, y;
  1473. {
  1474.     FsflatGroup    *groupPtr;
  1475.  
  1476.     for (groupPtr = aWindow->groupList; groupPtr != NULL;
  1477.         groupPtr = groupPtr->nextPtr) {
  1478.     if ((groupPtr->x <= x && x <= groupPtr->x + groupPtr->length) &&
  1479.         (groupPtr->y <= y && y <= groupPtr->y + aWindow->rowHeight)) {
  1480.         return groupPtr;
  1481.     }
  1482.     }
  1483.  
  1484.     return NULL;
  1485. }
  1486.  
  1487.  
  1488.  
  1489. /*
  1490.  *----------------------------------------------------------------------
  1491.  *
  1492.  * GetMaxEntryWidth --
  1493.  *
  1494.  *    Find the length of the longest column entry.
  1495.  *
  1496.  * Results:
  1497.  *    The length.
  1498.  *
  1499.  * Side effects:
  1500.  *    None.
  1501.  *
  1502.  *----------------------------------------------------------------------
  1503.  */
  1504. static int
  1505. GetMaxEntryWidth(aWindow)
  1506.     FsflatWindow    *aWindow;
  1507. {
  1508.     FsflatGroup    *tmpGroupPtr;
  1509.     FsflatFile    *tmpFilePtr;
  1510.     Boolean    getAttrsP = FALSE;
  1511.     int        charLength = 0;
  1512.     int        lbearing;
  1513.  
  1514.     if ((aWindow->displayInstructions & ~FSFLAT_NAME_FIELD) != 0) {
  1515.     getAttrsP = TRUE;
  1516.     }
  1517.     lbearing = -4;
  1518.     aWindow->maxNameLength = 0;
  1519.     /*
  1520.      * Warning: this allocates space width for the rules, even if they
  1521.      * are hidden groups.
  1522.      */
  1523.     for (tmpGroupPtr = aWindow->groupList; tmpGroupPtr != NULL;
  1524.         tmpGroupPtr = tmpGroupPtr->nextPtr) {
  1525.     charLength = strlen(tmpGroupPtr->rule);
  1526.     tmpGroupPtr->length =
  1527.         XTextWidth(aWindow->fontPtr, tmpGroupPtr->rule, charLength);
  1528.     if (charLength > aWindow->maxNameLength) {
  1529.         aWindow->maxNameLength = charLength;
  1530.     }
  1531.     for (tmpFilePtr = tmpGroupPtr->fileList; tmpFilePtr != NULL;
  1532.         tmpFilePtr = tmpFilePtr->nextPtr) {
  1533.         charLength = strlen(tmpFilePtr->name);
  1534.         tmpFilePtr->length =
  1535.             XTextWidth(aWindow->fontPtr, tmpFilePtr->name, charLength);
  1536.         if (charLength > aWindow->maxNameLength) {
  1537.         aWindow->maxNameLength = charLength;
  1538.         }
  1539.     }
  1540.     }
  1541.     aWindow->maxEntryWidth = aWindow->maxNameLength;
  1542.     /* 2 chars for spaces */
  1543.     aWindow->maxEntryWidth += 2;
  1544.     if (getAttrsP) {
  1545.     if (aWindow->displayInstructions & FSFLAT_ATIME_FIELD) {
  1546.         /* 24 chars needed for time, plus 2 spaces */
  1547.         aWindow->maxEntryWidth += 26;
  1548.     }
  1549.     if (aWindow->displayInstructions & FSFLAT_MTIME_FIELD) {
  1550.         /* 24 chars needed for time, plus two spaces */
  1551.         aWindow->maxEntryWidth += 26;
  1552.     }
  1553.     if (aWindow->displayInstructions & FSFLAT_DTIME_FIELD) {
  1554.         /* 24 chars needed for time, plus two spaces */
  1555.         aWindow->maxEntryWidth += 26;
  1556.     }
  1557.     if (aWindow->displayInstructions & FSFLAT_SIZE_FIELD) {
  1558.         /* 9 chars needed for time, plus two spaces */
  1559.         aWindow->maxEntryWidth += 11;
  1560.     }
  1561. #ifdef NOTDEF
  1562.     /* what to do about owner sizes, groups, plus perm. display? */
  1563.     if (aWindow->displayInstructions & FSFLAT_PERM_FIELD) {
  1564.         /* 1 chars needed for time, plus two spaces */
  1565.         aWindow->maxEntryWidth += 12;
  1566.     }
  1567.     if (aWindow->displayInstructions & FSFLAT_TYPE_FIELD) {
  1568.         /* 1 chars needed for time, plus two spaces */
  1569.         aWindow->maxEntryWidth += 12;
  1570.     }
  1571. #endif NOTDEF
  1572.     }
  1573.  
  1574.     /*
  1575.      * Plus lbearing cause we want to indent string enough that we don't draw
  1576.      * a box around it.
  1577.      */
  1578.     return (-lbearing +
  1579.         FSFLAT_CHAR_TO_WIDTH(aWindow->maxEntryWidth, aWindow->fontPtr));
  1580. }
  1581.  
  1582.  
  1583. /*
  1584.  *----------------------------------------------------------------------
  1585.  *
  1586.  * GetColumnWidthInfo --
  1587.  *
  1588.  *    Figure out the best fixed column width.  This includes the
  1589.  *    extra FSFLAT_COLUMN_SPACING added.  Also figure out the number
  1590.  *    of columns.
  1591.  *
  1592.  * Results:
  1593.  *    None.
  1594.  *
  1595.  * Side effects:
  1596.  *    The columnWidth and numCols parameters are filled in with their values.
  1597.  *
  1598.  *----------------------------------------------------------------------
  1599.  */
  1600. static void
  1601. GetColumnWidthInfo(aWindow, maxEntryWidth, columnWidth, numCols)
  1602.     FsflatWindow    *aWindow;
  1603.     int            maxEntryWidth;
  1604.     int            *columnWidth;
  1605.     int            *numCols;
  1606. {
  1607.     int        numToDisplay;
  1608.     int        numColsRequired;
  1609.     int        widthLeft;
  1610.  
  1611.     if (maxEntryWidth < 0) {
  1612.     *columnWidth = GetMaxEntryWidth(aWindow) + FSFLAT_COLUMN_SPACING;
  1613.     } else {
  1614.     *columnWidth = maxEntryWidth + FSFLAT_COLUMN_SPACING;
  1615.     }
  1616.     *numCols = aWindow->windowWidth / *columnWidth;
  1617.     if (*numCols == 0) {
  1618.     return ;
  1619.     }
  1620.     numToDisplay = aWindow->totalDisplayEntries - aWindow->firstElement + 1;
  1621.     if (aWindow->numRows == 0) {
  1622.     return ;
  1623.     }
  1624.     numColsRequired = numToDisplay / aWindow->numRows;
  1625.     if (numToDisplay % aWindow->numRows != 0) {
  1626.     numColsRequired++;
  1627.     }
  1628.     if (numColsRequired < *numCols) {
  1629.     *numCols = numColsRequired;
  1630.     }
  1631.     if (*numCols == 0) {
  1632.     return ;
  1633.     }
  1634.     widthLeft = aWindow->windowWidth - (*numCols * *columnWidth);
  1635.     /*
  1636.      * This could allow the last column to fail to meet the scroll bar by
  1637.      * a number of pixels one less than the number of columns.
  1638.      * We also add 1 pixel here so that entry window borders will overlap
  1639.      * with the window borders if we start them at 1 pixel before the
  1640.      * actual text area.
  1641.      */
  1642.     *columnWidth += (widthLeft / *numCols) + 1;
  1643.  
  1644.     return ;
  1645. }
  1646.  
  1647.  
  1648. /*
  1649.  *----------------------------------------------------------------------
  1650.  *
  1651.  * FigureWindowSize --
  1652.  *
  1653.  *    Figure out a good window size.
  1654.  *
  1655.  * Results:
  1656.  *    None.
  1657.  *
  1658.  * Side effects:
  1659.  *    The window size changes and stuff is laid out again to match.
  1660.  *
  1661.  *----------------------------------------------------------------------
  1662.  */
  1663. static void
  1664. FigureWindowSize(aWindow, maxEntryWidth)
  1665.     FsflatWindow    *aWindow;
  1666.     int            maxEntryWidth;
  1667. {
  1668.     int        maxWidth;
  1669.     int        width, height;
  1670.     int        columnWidth, numCols, numRows, numColsRequired;
  1671.  
  1672.     columnWidth = maxEntryWidth;
  1673.  
  1674.     maxWidth = fsflatRootWidth / 8 * 7;
  1675.     width = maxWidth;
  1676.  
  1677.     numCols = width / (columnWidth + FSFLAT_COLUMN_SPACING);
  1678.     if (numCols == 0) {
  1679.     /* just set to max size */
  1680.     }
  1681.  
  1682.     for ( ; ; ){
  1683.     /* Make it line up on column boundary -- no wasted space */
  1684.     width = numCols  * (columnWidth + FSFLAT_COLUMN_SPACING); 
  1685.     height = width / 3 * 2;        /* 2/3's of width */
  1686.     numRows = height / aWindow->rowHeight;
  1687.     if (aWindow->numRows == 0) {
  1688.         /* just set to max size */
  1689.     }
  1690.     numColsRequired = aWindow->totalDisplayEntries / numRows;
  1691.  
  1692.     if (aWindow->totalDisplayEntries % numRows != 0) {
  1693.         numColsRequired++;
  1694.     }
  1695.     if (numColsRequired < numCols) {
  1696.         numCols--;
  1697.     } else {
  1698.         break;
  1699.     }
  1700.     }
  1701.     /* last shrinking may have gone too far since we shrank rows as well */
  1702.     if (numColsRequired > numCols && (width + columnWidth +
  1703.         FSFLAT_COLUMN_SPACING <= maxWidth)) {
  1704.     numCols++;
  1705.     width += columnWidth + FSFLAT_COLUMN_SPACING;
  1706.     /* leave height and numRows alone */
  1707.     }
  1708.     /*
  1709.      * This next will generate an ExposureMask event, but I'm not sure
  1710.      * yet just where it fit in, so I may change some things.
  1711.      * It is an incredible pain that I can't change the displayWindow
  1712.      * to the correct dimensions and have the packer know to resize the
  1713.      * parent window.  Right now I have to resize to parent (surrounding)
  1714.      * window to what I guess should be its size.  I can't
  1715.      * XGetGeometry() them here since they all seem to have a size of 1
  1716.      * in Sx until some event occurs...  IS THIS STILL TRUE IN X11???
  1717.      */
  1718.     if (aWindow->windowWidth != width || aWindow->windowHeight != height) {
  1719.     XWindowChanges    changes;
  1720.  
  1721.     changes.width = width + 1 + Sx_ScrollbarWidth();
  1722.     changes.height = height + 
  1723.         (2 * Sx_DefaultHeight(fsflatDisplay, aWindow->titleFontPtr))
  1724.         + 3 + (4 * Sx_DefaultHeight(fsflatDisplay, aWindow->fontPtr));
  1725.     XConfigureWindow(fsflatDisplay, aWindow->surroundingWindow,
  1726.         CWWidth | CWHeight, &changes);
  1727.     }
  1728.  
  1729.     return;
  1730. }
  1731.